﻿#ifndef XQFTP_H
#define XQFTP_H
#include<QObject>
#include"XQHead.h"
#include"XQNework.h"
#include"XQUrlInfo.h"
#define XQFtpLog XQLog("XQFtp") //XQftp日志
class XQFtp : public QObject
{
    Q_OBJECT
public:
    explicit XQFtp(QObject *parent = 0);
    virtual ~XQFtp();
    //查询指定目录的列表信息
    static QList<XQUrlInfo> List(const QString& host, quint16 port = 21, const QString& dir = QString(), const QString& user = QString(), const QString& password = QString());
    //下载
    static void Get(const QString& host, quint16 port, const QString& remote_file, const QString& local_file, Ftp::TransferType type = Ftp::Binary, const QString& user = QString(), const QString& password = QString());
    //上传
    static void Put(const QString& host, quint16 port, const QString& remote_file, const QString& local_file, Ftp::TransferType type = Ftp::Binary, const QString& user = QString(), const QString& password = QString());
public:
    //设置主机地址和端口
    int setProxy(const QString &host, quint16 port);
    //链接主机
    int connectToHost(const QString &host, quint16 port=21);
    //登录
    int login(const QString &user = QString(), const QString &password = QString());
    //关闭连接
    int close();
    //设置传输模式
    int setTransferMode(Ftp::TransferMode mode);
    //查询指定目录的列表信息
    int list(const QString &dir = QString());
    //进入目录
    int cd(const QString &dir);
    //下载
    int get(const QString &file, QIODevice *dev=0, Ftp::TransferType type = Ftp::Binary);
    //下载到指定路径
    int get(const QString& remote_file, const QString& local_file, Ftp::TransferType type = Ftp::Binary);
    //上传
    int put(const QByteArray &data, const QString &file, Ftp::TransferType type = Ftp::Binary);
    //上传
    int put(QIODevice *dev, const QString &file, Ftp::TransferType type = Ftp::Binary);
    //上传指定文件
    int put(const QString& remote_file, const QString& local_file, Ftp::TransferType type = Ftp::Binary);
    //删除
    int remove(const QString &file);
    //创建目录
    int mkdir(const QString &dir);
    //递归创建目录
    int mkpath(const QString& path);
    //删除目录
    int rmdir(const QString &dir);
    //递归删除目录
    int rmpath(const QString& path);
    //重命名
    int rename(const QString &oldname, const QString &newname);
    //移动文件
    int move(const QString& oldfile, const QString& newfile);
    //原始命令
    int rawCommand(const QString &command); 
public:
    //等待状态变更
    bool waitForStateChange(Ftp::State state, int msecs = 3000);
    //等待连接上服务器
    bool waitForConnected(int msecs = 3000);
    //等待登录
    bool waitForLoggedIn(int msecs = 3000);
    //等待DTP输出传输结束 //get put list结束
    bool waitForFinished(int msecs = -1);
public:
    //获取可以从套接字中读取的字节数
    qint64 bytesAvailable() const;
    //读取数据
    qint64 read(char *data, qint64 maxlen);
    QByteArray readAll();
    //返回目录列表信息
    const QList<XQUrlInfo>& listInfo()const;
    //当前的id
    int currentId() const;
    QIODevice* currentDevice() const;
    Ftp::Command currentCommand() const;
    //是否还有等待的命令没处理
    bool hasPendingCommands() const;
    //清空剩余的等待命令
    void clearPendingCommands();
    //获取状态
    Ftp::State state() const;
    //获取错误码
    Ftp::Error error() const;
    //获取错误信息
    QString errorString() const;
    //是否是指定Debug模式
    bool isDebugModel(Ftp::Debug model);
public:
    //调试模式输出信息
    void setDebugModel(int model);
    void setDebugModel(Ftp::Debug model, bool open = true);
    //中断，终止连接
    void abort();
signals://信号
    //状态改变信号
    void stateChanged(Ftp::State);
    //列表信息信号
    void listInfo(const XQUrlInfo&);
    //准备读取信号
    void readyRead();
    //数据传输进度
    void dataTransferProgress(qint64 current, qint64 total);
    //原始命令准备完毕
    void rawCommandReply(int, const QString&);
    //命令开始
    void commandStarted(int id);
    //命令结束
    void commandFinished(int id, bool);
    //是否都处理完成了
    void done(bool);
protected slots:
    void _q_startNextCommand();
    void _q_piFinished(const QString&text);
    void _q_piError(int errorCode, const QString& text);
    void _q_piConnectState(int connectState);
    void _q_piFtpReply(int code, const QString& text);
    int addCommand(XQFtpCommand* cmd);
protected:
    static XQLog* m_log;//日志服务
    int m_debug = Ftp::Debug::error;//调试模式
    QList<XQUrlInfo> m_listInfo;//目录列表信息
    XQFtpPI* m_pi=nullptr;
    QList<XQFtpCommand*> m_pending;//命令列表
    bool m_close_waitForStateChange= false;
    Ftp::State m_state= Ftp::Unconnected;//状态
    Ftp::TransferMode m_transferMode= Ftp::Passive;//传输模式
    Ftp::Error m_error= Ftp::NoError;//错误码
    QString m_errorString= "Unknown error";//错误信息

    QString m_host = "127.0.0.1";
    quint16 m_port = 21;
    QString m_proxyHost;//代理主机
    quint16 m_proxyPort;//代理端口
};
#endif // QFTP_H
